#include "SessionBase.h"
#include "IdManager.h"
#include "SessionManager.h"
#include "ServerManager.h"
#include "IPacketParser.h"
#include "LogEx.h"
#include "StackTrace.h"
#include "Utils.h"
#include "msg_msgid.h"
#include "msg_common.h"
using namespace SGLib;

s32 CSessionBase::m_aliveInterval = 60; // sec

CSessionBase::CSessionBase(s32 id) : 
    CIoSocketEx(id)
{
	m_sessionId = 0;
    m_serverId = 0;
    m_lastBeat = 0;
    m_hasSendMessage = false;
}

CSessionBase::~CSessionBase()
{
}
    
void CSessionBase::OnAccept()
{
    m_lastBeat = (s64)time(NULL);
    _SetSessionId( CIdManager::Instance().GetNextId() );
	CSessionManager::Instance().AddSession( GetSessionId(), this, CServerManager::Instance().NeedCheckAlive() );
}

void CSessionBase::OnClose()
{
	CSessionManager::Instance().RemoveSession( GetSessionId() );
    if( GetServerId() != 0 )
    {
	    CSessionManager::Instance().RemoveServer( GetServerId(), this );
    }
    _SetSessionId( 0 );
    m_serverId = 0;
}

void CSessionBase::OnRecv(const byte *pkg, s32 len)
{
	IPacketParser *parser = _GetPacketParser();
	SELF_ASSERT( parser, return; );
	u32 msgid = parser->GetMsgId( pkg );
	s32 headlen = parser->GetHeadLen();
	pkg += headlen;
	len -= headlen;

    switch( msgid )
    {
    case commonproto::KEEP_ALIVE:
        _OnKeepAlive();
        break;
    case msgid::SERVER_REGISTER:
        _OnServerRegister( pkg, len );
        break;
    default:
	    _OnMessage( msgid, pkg, len );
        break;
    };
    m_hasSendMessage = true;
}

CIoSocketEx* CSessionBase::Clone(s32 id)
{
    return new CSessionBase( id );
}

u64 CSessionBase::GetSessionId()
{
    return m_sessionId;
}

u64 CSessionBase::GetServerId()
{
    return m_serverId;
}

bool CSessionBase::IsAlive()
{
    s64 now = (s64)time(NULL);
    s64 interval = now - m_lastBeat;
    if( interval <= (s64)m_aliveInterval )
    {
        return true;
    }
    return false;
}

bool CSessionBase::SendMsg(u32 msgid, const IMessage &msg)
{
    IPacketParser *parser = _GetPacketParser();
    SELF_ASSERT( parser, return false; );
    
    CHECK_SERIALIZE_MSG(msgid, msg, parser, return false;);
    if( !Send((byte*)msgbuffer, msglen) )
    {
        LOG_ERROR( "CSessionBase::SendMsg send failed. msgid[%u]", msgid );
        return false;
    }

    return true;
}

bool CSessionBase::SendMsgWithHead(u32 msgid, const IMessage &msg, char *head, int len)
{
	IPacketParser *parser = _GetPacketParser();
	SELF_ASSERT( parser, return false; );
	
	char buf[CIoSocketEx::E_MaxPkg_Len];

	s32 headlen = parser->GetHeadLen();
	s32 msglen = msg.SerializeToArray( buf+headlen+len, sizeof(buf)-headlen-len );
	if( msglen == IMessage::E_Error )
	{
		return false;
	}

	memcpy( buf+headlen, head, len );

	s32 totallen = msglen + headlen + len;
	parser->FillHeader( (byte*)buf, totallen, msgid );

	if( !Send((byte*)buf, totallen) )
	{
		LOG_ERROR( "CSessionBase::SendMsgWithHead send failed. msgid[%u]", msgid );
		return false;
	}

	return true;
}

bool CSessionBase::SendMsg(u32 msgid, const char *msg, s32 msglen)
{
    IPacketParser *parser = _GetPacketParser();
	SELF_ASSERT( parser, return false; );
	char buf[CIoSocketEx::E_MaxPkg_Len];
	s32 headlen = parser->GetHeadLen();

    memcpy( buf+headlen, msg, msglen );
	s32 totallen = msglen + headlen;
	parser->FillHeader( (byte*)buf, totallen, msgid );
	if( !Send((byte*)buf, totallen) )
	{
		LOG_ERROR( "CSessionBase::SendMsg 2 send failed. msgid[%u]", msgid );
		return false;
	}

	return true;
}

void CSessionBase::_SetSessionId(u64 id)
{
    m_sessionId = id;
}

void CSessionBase::_Clean()
{
    m_sessionId = 0;
    m_serverId = 0;
    m_lastBeat = (s64)time(NULL);
    m_hasSendMessage = false;
}

void CSessionBase::_OnKeepAlive()
{
    u64 sid = m_sessionId;
    if( IsAlive() )
    {   
        m_lastBeat = (s64)time(NULL);

        commonproto::KeepAlive msg;
	    bool ret = SendMsg( commonproto::KEEP_ALIVE, msg );
        //SELF_ASSERT( ret, return; );
#if 1
        LOG_DEBUG( "[%s][%s][%d] session[%llu] serverid[%llu] alive ret[%d] aliveInterval[%d]", 
            __FILE__, __FUNCTION__, __LINE__, sid, GetServerId(), ret?1:0, m_aliveInterval );
#endif
    }   
    else
    {   
        LOG_WARN( "[%s][%s][%d] id[%llu] client[%llu] serverid[%llu] aliveInterval[%d] not alive, close", 
                __FILE__, __FUNCTION__, __LINE__, sid, GetServerId(), m_aliveInterval );
        Close();
    }   
}

void CSessionBase::_OnServerRegister(const byte *pkg, s32 len)
{
    msgid::ServerRegister msg;
    CHECK_PARSE_MSG(msg, pkg, len);
    m_serverId = msg.serverid;
	CSessionManager::Instance().AddServer( GetServerId(), this );
    LOG_INFO( "[%s][%s][%d] serverid[%llu]", 
        __FILE__, __FUNCTION__, __LINE__, msg.serverid );
}

